package main

import (
	"fmt"
	"myinterface"
)

func main() {
	stu := myinterface.Student{"weiwei", "Golang is best language in the world"}
	var pe myinterface.People
	pe = &stu //student结构体方法实现了people接口的所有方法，就可以将该结构体赋值给接口对象;结构体只要有一个实现函数使用了指针接收器，就必须使用地址复制给接口变量，
	pe.SetName("uuuu")
	name := pe.ReturnName()
	fmt.Println(name)
	fmt.Println(stu.Name)

	tea := myinterface.Teacher{"fffff"}
	pe = &tea //teacher结构体方法实现了people接口的所有方法，就可以将该结构体赋值给接口对象

	pe.SetName("aaaa") //pe调用其自身的声明的setName方法，具体的表现形式取决于赋值给pe的结构体中实现people接口的方法
	tname := pe.ReturnName()
	fmt.Println("tname:", tname)
	fmt.Println("tea.name:", tea.Name)

	var study myinterface.Study
	study = &stu //student又实现了Study接口的所有方法，所以两个接口变量都可以用该结构体赋值
	study.Write("golang is best language in the world!")
	fmt.Println("oldNote:", stu.Note)
	newNote := study.Read()
	fmt.Println("newNote:", newNote)

	var interfaceCopy myinterface.Copy
	interfaceCopy = &stu //copy接口继承了people和study接口,因为student实现了people和study接口函数，进而相当于实现了copy的全部方法，所以可以赋值给copy接口
	fmt.Println("stu.Note:", stu.Note)
	interfaceCopy.Write("note changed") //stutent实现了study的Write，所以可以调用
	fmt.Println("stu.Note:", stu.Note)
	interfaceCopy.SetName("new name") //stutent实现了people的SetName，所以可以调用
	fmt.Println("name:", interfaceCopy.ReturnName())
	interfaceCopy.PrintNote()

	//interfaceCopy = &tea //teacher没有实现study接口函数，进而没有实现copy的全部方法，因此不能赋值

	interfaceGetStructName := interfaceCopy.(*myinterface.Student).Name //可以使用接口变量调用其指向的结构体中的成员变量；这里如果为了解耦需要对类型进行判断，不同类型的结构体可能存在不同的成员变量
	fmt.Println("inferfaceGetStructName:", interfaceGetStructName)

	fmt.Printf("interfaceCopy: %T %v\n", interfaceCopy, interfaceCopy)

	//interfaceCopy = &myinterface.Student2{"name2"}
	interfaceGetStruct, ok := interfaceCopy.(*myinterface.Student2) //因为interfaceCopy接口变量赋值成Student类型，不能调用Student2类型的成员变量
	if ok {
		fmt.Println("interfaceGetStruct.Name:", interfaceGetStruct.Name)
	} else {
		fmt.Println("这样就可以直接调用成员变量，通过判断ok来让程序不会异常")
	}

	stu2 := myinterface.Student2{"weiwei", "jizhang"}
	interfaceGetStruct = &stu2
	//student2赋值给接口变量后，如果不实现String方法会打印：&{weiwei jizhang}
	//student2赋值给接口变量后，如果实现String方法会打印：student2's Name:weiwei Note:jizhang
	fmt.Println(interfaceGetStruct)

}
